package com.codeduck.mp.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codeduck.mp.entity.Role;
import com.codeduck.mp.entity.ServiceResponse;
import com.codeduck.mp.entity.User;
import com.codeduck.mp.mapper.RoleMapper;
import com.codeduck.mp.mapper.UserMapper;
import com.codeduck.mp.service.IRoleService;
import com.codeduck.mp.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 事务回滚测试
 *
 * @author: <a href="mailto:codeduck@163.com">Codeduck</a>
 * @createDate: 2021-12-30
 */
@Service
@Slf4j
// isolation 数据库隔离级别
@Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private IRoleService roleService;

    /**
     * 实验总结：
     *  1. 主方法中若涉及多处事务回滚的方法，需要设置 Propagation.REQUIRED（如果没有事务，则新建一个事务，如果已经存在事务，其他的事务则加入到已存在的事务中）
     *  2. 在 1 的基础上，所有方法中的异常需要主动抛出，这样 Spring-Transactional 才能捕获到被调用的方法出现了异常，需要全局回滚所有涉及到的事务
     *  3. 切勿在主逻辑方法中 主动的捕获处理 各个事务方法抛出的异常，否则 Spring-Transactional 将无法察觉异常， 进而无法进行全局事务回滚
     *  4. 所以 所有的事务方法，包括主事务逻辑方法，全部主动抛出异常，让 Spring-Transactional 去捕获，这样就能够保证事务链的全局回滚操作。
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public ServiceResponse addUserAndRoleInfo(User user, Role role) throws Exception {
        log.info("addUserAndRoleInfo 方法开始执行……");
        ServiceResponse res = new ServiceResponse("操作成功", true);

        res = middleMethod(user, role);
        // 模拟第三种insert方法
        role.setRoleName("普通用户");
        role.setRoleId(null);
        res = addRole(role);
        int i = 1/0;
        return res;
    }

    private ServiceResponse middleMethod(User user, Role role) throws Exception {
        ServiceResponse serviceResponse = addUser(user);
        serviceResponse = addRole(role);
        return serviceResponse;
    }

    private ServiceResponse addUser(User user) throws Exception {
        ServiceResponse res = new ServiceResponse("操作成功", true);
        if (StringUtils.isBlank(user.getUsername())) {
            throw new Exception("用户名称不能为空");
        }
        int insertRes = userMapper.insert(user);
        if (insertRes <= 0) {
            throw new Exception("新增用户信息失败");
        }
        return res;
    }


    private ServiceResponse addRole(Role role) throws Exception {
        ServiceResponse res = new ServiceResponse("操作成功", true);
        if (StringUtils.isBlank(role.getRoleName())) {
            throw new Exception("角色名称不能为空");
        }
        int addRes = roleService.addRole(role);
        if (addRes <= 0) {
            throw new Exception("角色信息新增失败");
        }
        return res;
    }



}
